2f60a8
@@ -26,7 +26,6 @@
import java.io.Writer;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -53,6 +52,7 @@
import org.apache.commons.configuration.resolver.DefaultEntityResolver;
 import org.apache.commons.configuration.resolver.EntityRegistry;
 import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.logging.LogFactory;
 import org.w3c.dom.Attr;
 import org.w3c.dom.CDATASection;
@@ -544,10 +544,13 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
      *
      * @param node the actual node
      * @param element the actual XML element
-     * @param elemRefs a flag whether references to the XML elements should be set
-     * @param trim a flag whether the text content of elements should be trimmed;
-     * this controls the whitespace handling
-     * @return a map with all attribute values extracted for the current node
+     * @param elemRefs a flag whether references to the XML elements should be
+     *        set
+     * @param trim a flag whether the text content of elements should be
+     *        trimmed; this controls the whitespace handling
+     * @return a map with all attribute values extracted for the current node;
+     *         this map also contains the value of the trim flag for this node
+     *         under the key {@value #ATTR_SPACE}
      */
     private Map<String, String> constructHierarchy(ConfigurationNode node,
             Element element, boolean elemRefs, boolean trim)
@@ -555,6 +558,7 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
         boolean trimFlag = shouldTrim(element, trim);
         Map<String, String> attributes =
                 processAttributes(node, element, elemRefs);
+        attributes.put(ATTR_SPACE, String.valueOf(trimFlag));
         StringBuilder buffer = new StringBuilder();
         NodeList list = element.getChildNodes();
         for (int i = 0; i < list.getLength(); i++)
@@ -568,7 +572,8 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
                 Map<String, String> attrmap =
                         constructHierarchy(childNode, child, elemRefs, trimFlag);
                 node.addChild(childNode);
-                handleDelimiters(node, childNode, trimFlag, attrmap);
+                Boolean childTrim = Boolean.valueOf(attrmap.remove(ATTR_SPACE));
+                handleDelimiters(node, childNode, childTrim.booleanValue(), attrmap);
             }
             else if (w3cNode instanceof Text)
             {
@@ -577,11 +582,7 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
             }
         }
 
-        String text = buffer.toString();
-        if (trimFlag)
-        {
-            text = text.trim();
-        }
+        String text = determineValue(node, buffer.toString(), trimFlag);
         if (text.length() > 0 || (!hasChildren(node) && node != getRootNode()))
         {
             node.setValue(text);
@@ -600,6 +601,28 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
         return node.getChildrenCount() > 0 || node.getAttributeCount() > 0;
     }
 
+    /**
+     * Determines the value of a configuration node. This method mainly checks
+     * whether the text value is to be trimmed or not. This is normally defined
+     * by the trim flag. However, if the node has children and its content is
+     * only whitespace, then it makes no sense to store any value; this would
+     * only scramble layout when the configuration is saved again.
+     *
+     * @param node the current {@code ConfigurationNode}
+     * @param content the text content of this node
+     * @param trimFlag the trim flag
+     * @return the value to be stored for this node
+     */
+    private static String determineValue(ConfigurationNode node,
+            String content, boolean trimFlag)
+    {
+        boolean shouldTrim =
+                trimFlag
+                        || (StringUtils.isBlank(content) && node
+                                .getChildrenCount() > 0);
+        return shouldTrim ? content.trim() : content;
+    }
+
     /**
      * Helper method for constructing node objects for the attributes of the
      * given XML element.
@@ -613,15 +636,7 @@
public class XMLConfiguration extends BaseHierarchicalConfiguration implements
             Element element, boolean elemRefs)
     {
         NamedNodeMap attributes = element.getAttributes();
-        Map<String, String> attrmap;
-        if (attributes.getLength() > 0)
-        {
-            attrmap = new HashMap<String, String>();
-        }
-        else
-        {
-            attrmap = Collections.emptyMap();
-        }
+        Map<String, String> attrmap = new HashMap<String, String>();
 
         for (int i = 0; i < attributes.getLength(); ++i)
         {
